#pragma once
#include <vector>
#include <array>
#include <string>
#include <map>
#include <set>
#include "GridModel.h"

/**
 * @brief 三维点结构体
 * 
 * 用于存储空间点的坐标和类型信息
 */
struct Point3D {
    double x, y, z;
    int type;  // 添加类型字段，用于标记点所属的界面类型
    
    Point3D(double x_ = 0, double y_ = 0, double z_ = 0, int type_ = 0)
        : x(x_), y(y_), z(z_), type(type_) {}
    
    // 添加比较运算符，用于排序和查找
    bool operator<(const Point3D& other) const {
        if (x != other.x) return x < other.x;
        if (y != other.y) return y < other.y;
        return z < other.z;
    }
    
    bool operator==(const Point3D& other) const {
        return x == other.x && y == other.y && z == other.z;
    }
};

/**
 * @brief 三角形单元结构体
 * 
 * 用于存储三角形单元的顶点索引
 */
struct Triangle {
    size_t v1, v2, v3;  ///< 三角形的三个顶点索引
};

/**
 * @brief 四边形单元结构体
 * 
 * 用于存储四边形单元的顶点索引
 */
struct Quad {
    size_t v1, v2, v3, v4;  ///< 四边形的四个顶点索引
};

/**
 * @brief 断层节点结构体
 * 
 * 用于存储断层数据中的节点信息
 */
struct FaultNode {
    double x, y, z;
    int column_id;  // 修改为column_id
    std::string fault_name;  // 修改为fault_name
};

/**
 * @brief 柱线结构体
 */
struct PillarLine {
    int i, j;           ///< 柱线在网格中的位置
    double topZ;        ///< 柱线顶部z坐标
    double bottomZ;     ///< 柱线底部z坐标
    std::vector<double> nodeZs;  ///< 柱线上节点的z坐标
};

/**
 * @brief 断层柱线对结构体
 */
struct FaultPillarPair {
    PillarLine pillar1;
    PillarLine pillar2;
    bool operator<(const FaultPillarPair& other) const {
        if (pillar1.i != other.pillar1.i) return pillar1.i < other.pillar1.i;
        if (pillar1.j != other.pillar1.j) return pillar1.j < other.pillar1.j;
        if (pillar2.i != other.pillar2.i) return pillar2.i < other.pillar2.i;
        return pillar2.j < other.pillar2.j;
    }
};

/**
 * @brief 方向枚举类
 * 
 * 用于指定网格的方向
 */
enum class Direction {
    I,  ///< I方向（对应X轴）
    J   ///< J方向（对应Y轴）
};

/**
 * @brief 断层数据结构体
 */
struct FaultData {
    std::string name;  ///< 断层名称
    std::vector<FaultNode> nodes;  ///< 断层节点列表
};

/**
 * @brief 界面提取器类
 * 
 * 用于从角点网格模型中提取层界面和断层界面
 */
class SurfaceExtractor {
public:
    /**
     * @brief 构造函数
     * @param model 角点网格模型对象
     */
    explicit SurfaceExtractor(const GridModel& model);

    /**
     * @brief 提取地层界面和断层界面
     */
    void extractSurfaces();

    /**
     * @brief 获取顶点数据
     * @return 顶点数据向量的常引用
     */
    const std::vector<Point3D>& getVertices() const { return vertices; }

    /**
     * @brief 获取地层三角形单元数据
     * @return 三角形单元数据向量的常引用
     */
    const std::vector<Triangle>& getStrataTriangles() const { return strataTriangles; }

    /**
     * @brief 获取断层四边形单元数据
     * @return 四边形单元数据向量的常引用
     */
    const std::vector<Quad>& getFaultQuads() const { return faultQuads; }

    /**
     * @brief 获取地层四边形单元数据
     * @return 四边形单元数据向量的常引用
     */
    const std::vector<Quad>& getStrataQuads() const { return strataQuads; }

    /**
     * @brief 将界面数据写入VTK文件
     * @param filename 输出文件路径
     */
    void writeToFile(const std::string& filename) const;

    /**
     * @brief 从文件加载断层数据
     * @param filename 断层数据文件路径
     */
    void loadFaultData(const std::string& filename);

    /**
     * @brief 获取断层数据
     * @return 断层数据向量的常引用
     */
    const std::vector<FaultData>& getFaultData() const { return faultData; }

private:
    /**
     * @brief 检查两个z坐标是否相等（考虑浮点数误差）
     */
    bool isZCoordEqual(double z1, double z2) const;

    /**
     * @brief 检查两条边是否重合
     */
    bool isEdgeCoincident(const std::vector<double>& edge1Zs, const std::vector<double>& edge2Zs) const;

    /**
     * @brief 获取柱线的z坐标值
     */
    std::vector<double> getPillarZCoords(int i, int j) const;

    /**
     * @brief 处理相邻单元的共用边
     * @param i1,j1 第一个单元的i,j索引
     * @param i2,j2 第二个单元的i,j索引
     * @param k 当前处理的层索引
     */
    void processSharedEdge(int i1, int j1, int i2, int j2, int k);

    /**
     * @brief 创建断层面片
     */
    void createFaultSurfaces();

    /**
     * @brief 添加地层四边形
     * @param p1,p2,p3,p4 四边形的四个顶点
     */
    void addStrataQuad(const Point3D& p1, const Point3D& p2, const Point3D& p3, const Point3D& p4);

    /**
     * @brief 添加断层四边形
     * @param p1,p2,p3,p4 四边形的四个顶点
     */
    void addFaultQuad(const Point3D& p1, const Point3D& p2, const Point3D& p3, const Point3D& p4);

    /**
     * @brief 添加唯一顶点
     * @param point 要添加的顶点
     * @return 顶点在vertices数组中的索引
     */
    size_t addUniqueVertex(const Point3D& point);

    /**
     * @brief 获取节点类型
     * @param point 节点坐标
     * @return 节点类型(0-20)
     */
    int getPointType(const Point3D& point) const;

    const GridModel& gridModel;           ///< 角点网格模型的引用
    std::vector<Point3D> vertices;        ///< 所有顶点数据
    std::vector<Triangle> strataTriangles; ///< 地层界面的三角形单元
    std::vector<Quad> faultQuads;         ///< 断层界面的四边形单元
    std::vector<FaultNode> faultNodes;    ///< 断层节点数据
    std::vector<Quad> strataQuads;        ///< 地层界面的四边形单元
    std::set<FaultPillarPair> faultPillarPairs;  ///< 存储断层柱线对
    const double zTolerance = 1e-6;  ///< z坐标比较的容差
    std::vector<FaultData> faultData;  ///< 存储所有断层数据
}; 